package com.huilan.base.esl.service.fs;

import cn.hutool.core.util.StrUtil;
import com.huilan.base.esl.pojo.fs.EslEventEnum;
import com.huilan.base.esl.service.exeception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.freeswitch.esl.client.IEslEventListener;
import org.freeswitch.esl.client.inbound.Client;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @Description: 注入esl client
 * @Author: liuwc
 * @Date: 2020/1/15 17:20
 */
@Slf4j
@Component
public class EslClient implements ApplicationRunner {

    @Autowired
    private FsConfig fsConfig;
    private Client client;

    public String getHost(String id){
        List<FsServer> collect = fsConfig.getServer().stream().filter(s -> StrUtil.equalsIgnoreCase(s.getId(), id)).collect(Collectors.toList());
        if (collect.size() == 0)
            return "";
        else {
            return collect.get(0).getHost();
        }
    }
    @Override
    public void run(ApplicationArguments args) {
        initEventBean();
        FsServer fsServer = fsConfig.getServer().get(0);
        // 连接
        connect(fsServer);
        //检查连接
        checkClient(fsServer);
    }

    public Client getClient() {
        return client;
    }

    public void checkClient(FsServer fsServer) {
        //单独起1个线程，定时检测连接状态
        new ScheduledThreadPoolExecutor(1).scheduleAtFixedRate(() -> {
                if (client.canSend() == false) {
                    reConnect(fsServer);
                }
        }, 1, 1000, TimeUnit.MILLISECONDS);
    }

    public Client connect(FsServer fsServer) {
        client = new Client();
        try {
            log.info("fs connect begin");
            client.connect(fsServer.getHost(), fsServer.getPort(), fsServer.getPassword(), fsServer.getTimeout());
            Thread.sleep(500);
            client.setEventSubscriptions("plain", "all");
            log.info("过滤监听事件");
            List<String> eventsName = getEventsNames();
            eventsName.forEach(s -> {
                client.addEventFilter("Event-Name", s);
                log.info("event name:{}", s);
            });
            List<String> eventsSubclass = getEventsSubclass();
            eventsSubclass.forEach(s -> {
                client.addEventFilter("Event-Subclass", s);
                log.info("event Subclass:{}", s);
            });
            log.info("fs connect success");
        } catch (Exception e) {
            log.error("fs connect Exception",e);
        }
        return client;
    }

    public void reConnect(FsServer fsServer) {
        try {
            log.info("fs reConnect");
            client.connect(fsServer.getHost(), fsServer.getPort(), fsServer.getPassword(), fsServer.getTimeout());
            //移除事件
            client.cancelEventSubscriptions();
            Thread.sleep(500);
            log.info("移除所有事件");
            //移除事件
            client.cancelEventSubscriptions();
            //设置监听事件
            client.setEventSubscriptions("plain", "all");
            log.info("过滤监听事件");
            List<String> eventsName = getEventsNames();
            eventsName.forEach(s -> {
                client.addEventFilter("Event-Name", s);
                log.info("event name:{}", s);
            });
            List<String> eventsSubclass = getEventsSubclass();
            eventsSubclass.forEach(s -> {
                client.addEventFilter("Event-Subclass", s);
                log.info("event Subclass:{}", s);
            });
            log.info("fs reConnect success");
        } catch (Exception e) {
            log.error("fs reConnect Exception",e);
            try {
                client.close();
            }catch (Exception e1){
            }
        }
    }

    @Autowired
    private ApplicationContext applicationContext;
    public static Map<String, EslEventEnum> eventHandlerEnumMap = new ConcurrentHashMap<>();

    private void initEventBean() {
        log.info("注入事件处理bean");
        for (EslEventEnum s : EslEventEnum.values()) {
            s.setBean(applicationContext.getBean(s.getBeanName()));
            String key = s.name();
            if (StrUtil.isNotEmpty(s.getSubclass())) {
                key = s.getSubclass();
            }
            eventHandlerEnumMap.put(key.toLowerCase(), s);
        }
    }
    public static EslEventEnum getBeanByEventName(String eventName, String subclass) {
        String key = eventName;
        if (StrUtil.isNotEmpty(subclass)) {
            key = subclass;
        }
        EslEventEnum event = eventHandlerEnumMap.get(key.toLowerCase());
        if (event == null) {
            throw BusinessException.builder().msg("未设置事件处理对象").build();
        }
        return event;
    }
    private List<String> getEventsNames() {
        List<String> names = Stream.of(EslEventEnum.values())
                .filter(s -> s.isHandle() && StrUtil.isEmpty(s.getSubclass()))
                .map(s -> s.name().toUpperCase())
                .collect(Collectors.toList());
        return names;
    }

    private List<String> getEventsSubclass() {
        List<String> names = Stream.of(EslEventEnum.values())
                .filter(s -> s.isHandle() && StrUtil.isNotEmpty(s.getSubclass()))
                .map(s -> s.getSubclass())
                .collect(Collectors.toList());
        return names;
    }

}
